<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hierarchical Medical Dataset Explorer</title>
<style>
  :root{--bg:#0b1220;--panel:#131a2a;--muted:#b9c2d6;--ink:#eaf0ff;--brand:#5aa9ff;--chip:#1c2540;--border:#24304a}
  html,body{margin:0;padding:0;background:var(--bg);color:var(--ink);font-family:Inter,system-ui,Segoe UI,Arial}
  h1{font-size:24px;margin:20px}
  .wrap{max-width:1240px;margin:0 auto;padding:0 16px 80px}
  .grid{display:grid;gap:16px}
  .panel{background:var(--panel);border-radius:16px;padding:16px;box-shadow:0 6px 24px rgba(0,0,0,.25)}
  .hint{color:var(--muted);font-size:12px}
  .matrix{overflow:auto}
  table{border-collapse:separate;border-spacing:0;width:100%;min-width:820px}
  th,td{border:1px solid var(--border);padding:10px 12px;text-align:center}
  thead th{background:#0f1626;position:sticky;top:0;z-index:1}
  th.rowhdr{background:#0f1626;position:sticky;left:0;z-index:1}
  td button{width:100%;background:#111a2e;color:var(--ink);border:1px solid var(--border);border-radius:10px;padding:10px;cursor:pointer}
  td button.active, .chip.active, th.toggle.active{outline:2px solid var(--brand);box-shadow:0 0 0 2px rgba(90,169,255,.25) inset}
  th.toggle{cursor:pointer}
  .filters{display:flex;gap:16px;flex-wrap:wrap;margin-top:10px}
  fieldset{border:1px solid var(--border);border-radius:12px;padding:10px 12px;min-width:240px}
  legend{padding:0 6px;color:var(--muted)}
  label{margin-right:12px;display:inline-flex;gap:6px;align-items:center}
  input[type="checkbox"]{transform:scale(1.1)}
  input[type="search"]{width:260px;background:#0b1220;color:var(--ink);border:1px solid var(--border);border-radius:8px;padding:8px}
  .results{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}
  .card{background:#0f1626;border:1px solid var(--border);border-radius:14px;padding:14px;display:flex;flex-direction:column;gap:8px}
  .card h3{margin:0 0 6px 0;font-size:16px}
  .meta{font-size:12px;color:var(--muted)}
  .badge{display:inline-block;padding:2px 8px;border:1px solid #2b3656;border-radius:999px;margin:2px;font-size:12px}
  .links a{color:var(--brand);text-decoration:none;margin-right:12px}
  .row{display:flex;justify-content:space-between;align-items:center}
  .kbd{font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; background:#0b1220;border:1px solid var(--border);padding:2px 6px;border-radius:6px}
</style>
</head>
<body>
  <h1>Hierarchical Medical Dataset Explorer</h1>
  <div class="wrap grid">

    <!-- Level 1: Specialties × Modalities matrix + multi-select side filters -->
    <section class="panel">
      <div class="row">
        <h2 style="margin:0;font-size:18px">Level 1 — Specialties × Modalities</h2>
        <div class="hint">
          Click cells to build a scoped selection. <strong>Multiple cells = AND</strong> (datasets must cover all selected cells).
        </div>
      </div>
      <div id="matrixL1" class="matrix" style="margin-top:8px"></div>
      <div class="filters">
        <fieldset>
          <legend>Specialties (multi-select)</legend>
          <div id="deptFilters"></div>
        </fieldset>
        <fieldset>
          <legend>Modalities (multi-select)</legend>
          <div id="modFilters"></div>
        </fieldset>
        <fieldset>
          <legend>Keyword</legend>
          <input id="q" type="search" placeholder="Search name, task, biomarker…" />
        </fieldset>
      </div>
      <div class="hint" id="countHint"></div>
    </section>

    <!-- Level 2: Disease/Biomarker × Sub-modality matrix (contextual to L1 active cells) -->
    <section class="panel">
      <div class="row" style="margin-bottom:8px">
        <h2 style="margin:0;font-size:18px">Level 2 — <span id="l2Title">Select one or more Level-1 cells</span></h2>
        <div class="hint">
          Toggle whole <span class="kbd">columns</span>/<span class="kbd">rows</span> via headers; toggle intersections by clicking cells.
          <strong>Multiple selections = AND</strong> (datasets must include all chosen diseases and sub-modalities).
        </div>
      </div>
      <div id="matrixL2" class="matrix"></div>
    </section>

    <!-- Results -->
    <section class="panel">
      <div class="row" style="margin-bottom:8px">
        <h2 style="margin:0;font-size:18px">Matching Datasets</h2>
        <div class="hint" id="resultCount"></div>
      </div>
      <div id="results" class="results"></div>
    </section>

  </div>

<script>
// ------------------------------
// Configuration (taxonomies)
// ------------------------------
const SPECIALTIES = ["Ophthalmology","Cardiology","Oncology","Neurology"]; // keep 4 per your original design
const MODALITIES  = ["Text","Image","Time-series"];

// Diseases/biomarkers by specialty (examples & additions)
const DISEASES_BY_SPEC = {
  Ophthalmology: ["Glaucoma","AMD","DR","DME","Myopia","Systemic biomarkers"],
  Cardiology:    ["Coronary Artery Disease","Arrhythmia","Heart Failure","Hypertension","Valvular Disease","Fetal Monitoring"],
  Oncology:      ["Breast Cancer","Lung Cancer","Colorectal Cancer","Glioma","Lymphoma","Lung disease"],
  Neurology:     ["Stroke","Alzheimer's Disease","Parkinson's","Epilepsy","MS","Sleep disorders"]
};

// Sub-modalities allowed per specialty & top-level modality category
const SUBMODS_IMAGE_BY_SPEC = {
  Ophthalmology: ["CFP","OCT","OCTA","SLO","FFA","Other"],         // +FFA
  Cardiology:    ["CT","Ultrasound","MRI","Coronary Angiogram","X-ray","Other"], // +X-ray for completeness
  Oncology:      ["CT","MRI","Ultrasound","Histopathology","X-ray","Other"],     // +X-ray for CXR
  Neurology:     ["MRI","CT","fMRI","Other"]
};
const SUBMODS_TS_BY_SPEC = {
  Ophthalmology: ["Eye-tracking","IOP sensor","Other"],
  Cardiology:    ["ECG","Blood Glucose Monitoring","Heartbeat IoT","Other"],
  Oncology:      ["Chemo schedule","Vitals stream","Other"],
  Neurology:     ["EEG","PSG","Wearable sensors","Other"]          // +PSG
};
const SUBMODS_TEXT_BY_SPEC = {
  Ophthalmology: ["Clinical notes","Reports","Referral letters","Radiology report","Other"], // +Radiology report (for FFA-IR text)
  Cardiology:    ["EHR notes","Echo reports","Cath lab reports","Radiology report","Other"],
  Oncology:      ["Pathology reports","Radiology reports","EHR notes","Other"],
  Neurology:     ["EHR notes","Radiology reports","Neuropsychology reports","Other"]
};

// ------------------------------
// Datasets list (examples + your 9 PhysioNet additions)
// ------------------------------
const datasets = [
  // --- Example seeds (keep if useful) ---
  {
    id:"eyepacs",
    name:"EyePACS",
    short_description:"Fundus images for diabetic retinopathy grading (5-class).",
    tasks:["Classification","Grading"],
    specialties:["Ophthalmology"],
    modalities:["Image"],
    submodalities:["CFP"],
    diseases:["DR"],
    biomarkers:[],
    population:{size:88000,regions:["US"],demographics:"Mixed"},
    labels:{label_types:["DR grade"],grading_scheme:"0–4"},
    access:"Open",
    license:"CC BY-NC 4.0",
    year:2015,
    updated_at:"2024-06-01",
    links:{homepage:"#",download:"#",documentation:"#"},
    citation:"Author et al., 2015.",
    keywords:["fundus","DR","ophthalmology"]
  },

  // ================== Your new datasets ==================

  // 1) Brazilian Ophthalmological Dataset
  {
    id:"brazilian-ophthalmological",
    name:"Brazilian Ophthalmological Dataset",
    short_description:"Ophthalmological exams from Brazilian patients with multi-disease labels.",
    tasks:["Classification","Multi-label"],
    specialties:["Ophthalmology"],
    modalities:["Image","Text"],
    submodalities:["CFP","FFA"],             // include FFA exposure (papers show angiography usage)
    diseases:["DR","DME","AMD","Myopia"],    // ensure DR & DME present
    biomarkers:["Vessel","Macula","Optic disc"],
    population:{size:null,regions:["Brazil"],demographics:""},
    labels:{label_types:["Multi-label"],grading_scheme:"ICDR/others"},
    access:"Controlled",
    license:"PhysioNet Credentialed",
    year:2024,
    updated_at:"2024-08-14",
    links:{
      homepage:"https://physionet.org/content/brazilian-ophthalmological/1.0.1/",
      download:"https://physionet.org/content/brazilian-ophthalmological/1.0.1/",
      documentation:"https://physionet.org/content/brazilian-ophthalmological/1.0.1/"
    },
    citation:"PhysioNet Brazilian Ophthalmological Dataset (v1.0.1)."
  },

  // 2) mBRSET
  {
    id:"mbrset",
    name:"mBRSET — Mobile Brazilian Retinal Dataset",
    short_description:"Smartphone/mobile retinal fundus images for multi-label screening.",
    tasks:["Screening","Multi-label classification"],
    specialties:["Ophthalmology"],
    modalities:["Image"],
    submodalities:["CFP"],
    diseases:["DR","DME","AMD","Glaucoma","Myopic fundus"], // BRSET-style label set (incl. DR & DME)
    biomarkers:["Quality"],
    population:{size:null,regions:["Brazil"],demographics:""},
    labels:{label_types:["Multi-label","Quality"],grading_scheme:"ICDR/SDRG"},
    access:"Controlled",
    license:"PhysioNet Credentialed",
    year:2024,
    updated_at:"2024-08-01",
    links:{
      homepage:"https://physionet.org/content/mbrset/1.0/",
      download:"https://physionet.org/content/mbrset/1.0/",
      documentation:"https://physionet.org/content/mbrset/1.0/"
    },
    citation:"mBRSET (PhysioNet v1.0)."
  },

  // 3) Hillel Yaffe Glaucoma Dataset
  {
    id:"hillel-yaffe-glaucoma",
    name:"Hillel Yaffe Glaucoma Dataset (HYGD)",
    short_description:"Fundus images with glaucoma labels and reference-standard annotations.",
    tasks:["Glaucoma detection","Classification"],
    specialties:["Ophthalmology"],
    modalities:["Image"],
    submodalities:["CFP"],
    diseases:["Glaucoma"],
    biomarkers:["CDR"],
    population:{size:null,regions:["IL"],demographics:""},
    labels:{label_types:["Glaucoma label","CDR"],grading_scheme:""},
    access:"Controlled",
    license:"PhysioNet Credentialed",
    year:2024,
    updated_at:"2024-09-01",
    links:{
      homepage:"https://physionet.org/content/hillel-yaffe-glaucoma-dataset/1.0.0/",
      download:"https://physionet.org/content/hillel-yaffe-glaucoma-dataset/1.0.0/",
      documentation:"https://physionet.org/content/hillel-yaffe-glaucoma-dataset/1.0.0/"
    },
    citation:"HYGD (PhysioNet v1.0.0)."
  },

  // 4) FFA-IR: ophthalmic angiography + reports
  {
    id:"ffa-ir-medical-report",
    name:"FFA-IR — Explainable Medical Report Generation Benchmark",
    short_description:"Fluorescein fundus angiography (FFA) images paired with clinical reports for explainable report generation.",
    tasks:["Report generation","VLM reasoning","Captioning"],
    specialties:["Ophthalmology"],
    modalities:["Image","Text"],
    submodalities:["FFA","Radiology report"],   // FFA + text reports
    diseases:["DR","DME","AMD"],
    biomarkers:["Leakage","Ischemia"],
    population:{size:null,regions:["CN"],demographics:""},
    labels:{label_types:["Reports","Lesion cues"],grading_scheme:""},
    access:"Controlled",
    license:"PhysioNet Credentialed",
    year:2024,
    updated_at:"2024-11-01",
    links:{
      homepage:"https://physionet.org/content/ffa-ir-medical-report/1.1.0/",
      download:"https://physionet.org/content/ffa-ir-medical-report/1.1.0/",
      documentation:"https://physionet.org/content/ffa-ir-medical-report/1.1.0/"
    },
    citation:"FFA-IR (PhysioNet v1.1.0)."
  },

  // 5) CAD-Chest: labels from MIMIC-CXR reports (TEXT)
  {
    id:"cad-chest",
    name:"CAD-Chest — Disease Annotations from MIMIC-CXR Reports",
    short_description:"Comprehensive disease labels derived from MIMIC-CXR radiology reports.",
    tasks:["NLP labeling","Weak supervision","Phenotype extraction"],
    specialties:["Oncology"],                 // mapped under Oncology to keep 4 specialties
    modalities:["Text"],
    submodalities:["Radiology report"],
    diseases:["Lung disease","Lung Cancer"],
    biomarkers:[],
    population:{size:null,regions:["US"],demographics:""},
    labels:{label_types:["Report-derived labels"],grading_scheme:""},
    access:"Controlled",
    license:"PhysioNet Credentialed",
    year:2023,
    updated_at:"2023-12-01",
    links:{
      homepage:"https://physionet.org/content/cad-chest/1.0/",
      download:"https://physionet.org/content/cad-chest/1.0/",
      documentation:"https://physionet.org/content/cad-chest/1.0/"
    },
    citation:"CAD-Chest (PhysioNet v1.0)."
  },

  // 6) adfecgdb: fetal ECG (time-series)
  {
    id:"adfecgdb",
    name:"Abdominal and Direct Fetal ECG Database (adfecgdb)",
    short_description:"Fetal ECG recordings from abdominal and direct leads for fetal monitoring research.",
    tasks:["Signal processing","Fetal HR extraction"],
    specialties:["Cardiology"],
    modalities:["Time-series"],
    submodalities:["ECG"],
    diseases:["Fetal Monitoring"],
    biomarkers:["FHR"],
    population:{size:null,regions:["EU"],demographics:""},
    labels:{label_types:["Beat annotations"],grading_scheme:""},
    access:"Open",
    license:"PhysioNet Open",
    year:2013,
    updated_at:"2013-01-01",
    links:{
      homepage:"https://physionet.org/content/adfecgdb/",
      download:"https://physionet.org/content/adfecgdb/",
      documentation:"https://physionet.org/content/adfecgdb/"
    },
    citation:"adfecgdb (PhysioNet)."
  },

  // 7) Discharge summary templates (text)
  {
    id:"discharge-summary-templates",
    name:"Annotated MIMIC-IV Discharge Summary Templates",
    short_description:"Annotated discharge summaries for de-identification and template extraction.",
    tasks:["De-identification","Template extraction"],
    specialties:["Ophthalmology","Cardiology","Oncology","Neurology"], // cross-specialty text resource
    modalities:["Text"],
    submodalities:["Clinical notes"],
    diseases:[],
    biomarkers:[],
    population:{size:null,regions:["US"],demographics:""},
    labels:{label_types:["Entities","Templates"],grading_scheme:""},
    access:"Controlled",
    license:"PhysioNet Credentialed",
    year:2024,
    updated_at:"2024-06-01",
    links:{
      homepage:"https://physionet.org/content/discharge-summary-templates/",
      download:"https://physionet.org/content/discharge-summary-templates/",
      documentation:"https://physionet.org/content/discharge-summary-templates/"
    },
    citation:"PhysioNet (MIMIC-IV Discharge Templates)."
  },

  // 8) Lung segmentation (CXR images)
  {
    id:"lung-segment-mimic-cxr",
    name:"Chest X-ray Segmentation Images (MIMIC-CXR)",
    short_description:"Segmentation masks for chest X-rays derived from MIMIC-CXR.",
    tasks:["Segmentation"],
    specialties:["Oncology"],                   // mapped under Oncology to keep 4 specialties
    modalities:["Image"],
    submodalities:["X-ray"],
    diseases:["Lung disease","Lung Cancer"],
    biomarkers:["Lung fields"],
    population:{size:null,regions:["US"],demographics:""},
    labels:{label_types:["Masks"],grading_scheme:""},
    access:"Controlled",
    license:"PhysioNet Credentialed",
    year:2023,
    updated_at:"2023-11-01",
    links:{
      homepage:"https://physionet.org/content/lung-segment-mimic-cxr/",
      download:"https://physionet.org/content/lung-segment-mimic-cxr/",
      documentation:"https://physionet.org/content/lung-segment-mimic-cxr/"
    },
    citation:"PhysioNet (MIMIC-CXR Segmentation)."
  },

  // 9) Sleep-EDFx (EEG/PSG)
  {
    id:"sleep-edfx",
    name:"Sleep-EDF Database Expanded (Sleep-EDFx)",
    short_description:"Polysomnography recordings (EEG, EOG, EMG, ECG) with sleep stage annotations.",
    tasks:["Sleep staging","Arousal detection"],
    specialties:["Neurology"],
    modalities:["Time-series"],
    submodalities:["EEG","PSG"],
    diseases:["Sleep disorders"],
    biomarkers:["Sleep stages"],
    population:{size:null,regions:["EU"],demographics:""},
    labels:{label_types:["Sleep stage labels"],grading_scheme:"AASM/R&K"},
    access:"Open",
    license:"PhysioNet Open",
    year:2013,
    updated_at:"2018-01-01",
    links:{
      homepage:"https://physionet.org/content/sleep-edfx/",
      download:"https://physionet.org/content/sleep-edfx/",
      documentation:"https://physionet.org/content/sleep-edfx/"
    },
    citation:"Kemp et al., PhysioNet."
  }
];

// ------------------------------
// State
// ------------------------------
const state = {
  specs: new Set(SPECIALTIES),   // Level-1 checkbox filters
  mods:  new Set(MODALITIES),
  q: "",
  activeCells: new Set(),        // multiple Level-1 cells, key = `${mod}__${spec}`
  l2: {
    diseases: new Set(),         // AND filters in Level-2
    submods:  new Set()
  }
};

// ------------------------------
// DOM refs
// ------------------------------
const elL1 = document.getElementById('matrixL1');
const elDeptFilters = document.getElementById('deptFilters');
const elModFilters  = document.getElementById('modFilters');
const elQ = document.getElementById('q');
const elCountHint = document.getElementById('countHint');
const elL2 = document.getElementById('matrixL2');
const elL2Title = document.getElementById('l2Title');
const elResults = document.getElementById('results');
const elResultCount = document.getElementById('resultCount');

// ------------------------------
// Helpers
// ------------------------------
const intersects = (set, arr) => { if (!set || set.size===0) return true; for (const x of arr||[]) if (set.has(x)) return true; return false; };
const includesAll = (set, arr) => { for (const x of set) if (!(arr||[]).includes(x)) return false; return true; };
function uniq(arr){ return [...new Set(arr||[])]; }
function sorted(arr){ return [...(arr||[])].sort((a,b)=>a.localeCompare(b)); }
function getSubmodsFor(spec, mod){
  if (!spec || !mod) return [];
  if (mod === 'Image')       return SUBMODS_IMAGE_BY_SPEC[spec] || [];
  if (mod === 'Time-series') return SUBMODS_TS_BY_SPEC[spec]    || [];
  if (mod === 'Text')        return SUBMODS_TEXT_BY_SPEC[spec]  || [];
  return [];
}

// Filter after Level-1 checkbox + keyword
function poolL1(){
  return datasets.filter(d=>{
    const okSpec = intersects(state.specs, d.specialties||d.departments);
    const okMod  = intersects(state.mods,  d.modalities);
    const okQ = !state.q || (
      (d.name||'').toLowerCase().includes(state.q) ||
      (d.short_description||'').toLowerCase().includes(state.q) ||
      (d.tasks||[]).join(' ').toLowerCase().includes(state.q) ||
      (d.diseases||[]).join(' ').toLowerCase().includes(state.q) ||
      (d.biomarkers||[]).join(' ').toLowerCase().includes(state.q) ||
      (d.keywords||[]).join(' ').toLowerCase().includes(state.q)
    );
    return okSpec && okMod && okQ;
  });
}

// Final list: satisfy AND across selected L1 cells AND across L2 selections
function poolFinal(){
  const base = poolL1();
  const l1Cells = [...state.activeCells].map(key=>{ const [mod,spec] = key.split('__'); return {mod,spec}; });

  return base.filter(d=>{
    // L1 AND scope: dataset must include each (mod,spec)
    const okL1 = l1Cells.every(({mod,spec})=> (d.modalities||[]).includes(mod) && ((d.specialties||d.departments||[]).includes(spec)) );
    if (!okL1) return false;

    // L2 AND scope: must include all selected diseases AND all selected submods
    const diseasePool = (d.diseases||[]).concat(d.biomarkers||[]);
    const okDisease = state.l2.diseases.size ? includesAll(state.l2.diseases, diseasePool) : true;
    const okSubmod  = state.l2.submods.size  ? includesAll(state.l2.submods,  d.submodalities||[]) : true;

    return okDisease && okSubmod;
  });
}

// ------------------------------
// Level 1 rendering (multi-cell AND)
// ------------------------------
function renderL1Matrix(){
  // counts per (mod, spec)
  const counts = {};
  for (const d of datasets){
    const specs = d.specialties || d.departments || [];
    for (const spec of specs){
      for (const mod of d.modalities||[]){
        const key = `${mod}__${spec}`;
        counts[key] = (counts[key]||0)+1;
      }
    }
  }
  let html = '<table><thead><tr><th>Modality \\\\ Specialty</th>';
  for (const spec of SPECIALTIES) html += `<th>${spec}</th>`;
  html += '</tr></thead><tbody>';
  for (const mod of MODALITIES){
    html += `<tr><th class="rowhdr">${mod}</th>`;
    for (const spec of SPECIALTIES){
      const key = `${mod}__${spec}`;
      const c = counts[key] || 0;
      const active = state.activeCells.has(key) ? 'active' : '';
      html += `<td><button class="${active}" data-spec="${spec}" data-mod="${mod}">${c} datasets</button></td>`;
    }
    html += '</tr>';
  }
  html += '</tbody></table>';
  elL1.innerHTML = html;

  // click -> toggle cell in activeCells (AND logic)
  elL1.querySelectorAll('button').forEach(btn=>{
    btn.addEventListener('click',()=>{
      const spec = btn.getAttribute('data-spec');
      const mod  = btn.getAttribute('data-mod');
      const key = `${mod}__${spec}`;
      state.activeCells.has(key) ? state.activeCells.delete(key) : state.activeCells.add(key);
      // Reset Level-2 when L1 selection changes
      state.l2.diseases.clear();
      state.l2.submods.clear();
      renderAll();
      elL2.scrollIntoView({behavior:'smooth',block:'start'});
    });
  });
}

function renderL1Filters(){
  elDeptFilters.innerHTML = SPECIALTIES.map(s=>`<label><input type="checkbox" value="${s}" ${state.specs.has(s)?'checked':''}/> ${s}</label>`).join('');
  elModFilters.innerHTML  = MODALITIES.map(m=>`<label><input type="checkbox" value="${m}" ${state.mods.has(m)?'checked':''}/> ${m}</label>`).join('');
  elDeptFilters.querySelectorAll('input').forEach(cb=>{
    cb.addEventListener('change',e=>{ const v=e.target.value; e.target.checked?state.specs.add(v):state.specs.delete(v); renderAll(); });
  });
  elModFilters.querySelectorAll('input').forEach(cb=>{
    cb.addEventListener('change',e=>{ const v=e.target.value; e.target.checked?state.mods.add(v):state.mods.delete(v); renderAll(); });
  });
  elQ.value = state.q;
  elQ.oninput = ()=>{ state.q = elQ.value.trim().toLowerCase(); renderAll(); };

  const total = datasets.length;
  const bySpec = [...state.specs].join(', ') || 'Any';
  const byMod  = [...state.mods].join(', ') || 'Any';
  const l1Sel  = [...state.activeCells].length ? ` | L1 cells: ${[...state.activeCells].map(x=>x.replace('__',' + ')).join('; ')}` : '';
  elCountHint.textContent = `Now filtering — Specialties: ${bySpec} | Modalities: ${byMod}${l1Sel} | Total datasets: ${total}`;
}

// ------------------------------
// Level 2 rendering (depends on selected L1 cells; union of options; AND filtering when selected)
// ------------------------------
function renderL2(){
  const l1Cells = [...state.activeCells].map(key=>{ const [mod,spec] = key.split('__'); return {mod,spec}; });
  if (l1Cells.length===0){
    elL2Title.textContent = 'Select one or more Level-1 cells';
    elL2.innerHTML = '<div class="hint" style="padding:8px">Pick cells in Level-1 to open a contextual matrix here (Diseases/Biomarkers × Sub-modalities). Multiple selections are combined with AND in results.</div>';
    return;
  }
  elL2Title.textContent = l1Cells.map(x=>`${x.spec} + ${x.mod}`).join('  •  ');

  // Aggregate diseases and submods across selected L1 cells (union of available options)
  const diseases = sorted(uniq(l1Cells.flatMap(({spec})=> DISEASES_BY_SPEC[spec] || [])));
  const submods  = sorted(uniq(l1Cells.flatMap(({spec,mod})=> getSubmodsFor(spec,mod))));

  // Build counts restricted to datasets that already satisfy L1 AND
  const base = datasets.filter(d=> l1Cells.every(({mod,spec})=> (d.modalities||[]).includes(mod) && ((d.specialties||d.departments||[]).includes(spec)) ));
  const counts = {};
  for (const ds of base){
    const diseasePool = (ds.diseases||[]).concat(ds.biomarkers||[]);
    for (const dis of diseases){
      if (!diseasePool.includes(dis)) continue;
      for (const sm of submods){
        if (!(ds.submodalities||[]).includes(sm)) continue;
        const key = `${dis}__${sm}`;
        counts[key] = (counts[key]||0)+1;
      }
    }
  }

  let html = '<table><thead><tr><th>Disease/Biomarker \\\\ Sub-modality</th>';
  for (const dis of diseases){
    const colActive = state.l2.diseases.has(dis) ? 'active' : '';
    html += `<th class="toggle ${colActive}" data-kind="disease" data-val="${dis}">${dis}</th>`;
  }
  html += '</tr></thead><tbody>';
  for (const sm of submods){
    const rowActive = state.l2.submods.has(sm) ? 'active' : '';
    html += `<tr><th class="rowhdr toggle ${rowActive}" data-kind="submod" data-val="${sm}">${sm}</th>`;
    for (const dis of diseases){
      const key = `${dis}__${sm}`;
      const n = counts[key] || 0;
      const isActive = state.l2.diseases.has(dis) && state.l2.submods.has(sm);
      html += `<td><button class="${isActive?'active':''}" data-disease="${dis}" data-submod="${sm}">${n}</button></td>`;
    }
    html += '</tr>';
  }
  html += '</tbody></table>';
  elL2.innerHTML = html;

  // Interactions
  elL2.querySelectorAll('td button').forEach(btn=>{
    btn.addEventListener('click',()=>{
      const d = btn.getAttribute('data-disease');
      const s = btn.getAttribute('data-submod');
      // AND builder: toggle each set independently
      state.l2.diseases.has(d) ? state.l2.diseases.delete(d) : state.l2.diseases.add(d);
      state.l2.submods.has(s)  ? state.l2.submods.delete(s)  : state.l2.submods.add(s);
      renderAll();
      elResults.scrollIntoView({behavior:'smooth',block:'start'});
    });
  });
  elL2.querySelectorAll('th.toggle[data-kind="disease"]').forEach(th=>{
    th.addEventListener('click',()=>{ const d=th.getAttribute('data-val'); state.l2.diseases.has(d)?state.l2.diseases.delete(d):state.l2.diseases.add(d); renderAll(); });
  });
  elL2.querySelectorAll('th.toggle[data-kind="submod"]').forEach(th=>{
    th.addEventListener('click',()=>{ const s=th.getAttribute('data-val'); state.l2.submods.has(s)?state.l2.submods.delete(s):state.l2.submods.add(s); renderAll(); });
  });
}

// ------------------------------
// Results rendering
// ------------------------------
function renderResults(){
  const items = poolFinal();
  elResultCount.textContent = `${items.length} dataset${items.length!==1?'s':''}`;
  elResults.innerHTML = items.map(d=>`
    <article class="card">
      <h3>${d.name}</h3>
      <div class="meta">${(d.specialties||d.departments).join(', ')} · ${d.modalities.join(', ')} ${d.submodalities?.length?('· '+d.submodalities.join(', ')):''}</div>
      <div>${d.short_description||''}</div>
      <div>
        ${(d.diseases||[]).slice(0,12).map(x=>`<span class="badge">${x}</span>`).join('')}
        ${(d.biomarkers||[]).slice(0,12).map(x=>`<span class="badge">${x}</span>`).join('')}
      </div>
      <div class="meta">Access: ${d.access||'—'} · License: ${d.license||'—'} · ${d.population?.size?('N='+d.population.size):''}</div>
      <div class="links">
        <a href="${d.links.homepage}" target="_blank" rel="noopener">Info</a>
        ${d.links.download?`<a href="${d.links.download}" target="_blank" rel="noopener">Download</a>`:''}
        ${d.links.documentation?`<a href="${d.links.documentation}" target="_blank" rel="noopener">Docs</a>`:''}
      </div>
    </article>
  `).join('') || `<div class="hint">No datasets match. Try removing some selections.</div>`;
}

// ------------------------------
// Orchestration
// ------------------------------
function renderAll(){
  renderL1Matrix();
  renderL1Filters();
  renderL2();
  renderResults();
}

// Init
renderAll();
</script>
</body>
</html>
